package Network.TCP;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class EchoServer {
    private ServerSocket serverSocket;

    public EchoServer(int port) throws IOException {
        //服务器启动，就会绑定到port端口上面
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("server stsrt");

        ExecutorService threadPool = Executors.newCachedThreadPool();      //线程池版本

        while(true) {
            //1.通过accept方法等待客户端连接，直到有客户端连接上来，accept方法才会返回
            //2.如果没有客户端连接上来，accept方法会阻塞等待
            //3.如果有客户端连接上来，accept方法会返回一个Socket对象，这个Socket对象就表示客户端和服务器之间的连接
            //4.通过这个Socket对象，就可以和客户端进行通信
            Socket socket = serverSocket.accept();

            //多线程版本
            // Thread t = new Thread(() -> {
            // //这个地方 this 指向的是当前的对象，和socket都是lambda从外层作用域中捕获的变量
            // this.processConnection(socket);
            // }); 
            // t.start();

            //线程池版本
            threadPool.submit(() -> {
                this.processConnection(socket);
            });

        }
    }

    private void processConnection(Socket socket)  {
        System.out.printf("[%s:%d] client online\n",socket.getInetAddress().toString(),socket.getPort());
        try (InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream()) {
            //实现通信的代码
            //一个客户端可能会和服务器通信多次，所以要使用循环
            Scanner scanner = new Scanner(inputStream);
            PrintWriter writer = new PrintWriter(outputStream);
            
            while(true) {
                //1.从socket中读取客户端发送过来的数据并解析
                if (!scanner.hasNext()) {
                    //针对客户端下线的逻辑处理，如果客户端下线（断开连接），则结束循环
                    //此时hasNext()方法会返回false，就会结束循环
                    //如果是使用read方法，就会出现返回-1的情况，也会结束循环
                    System.out.printf("[%s:%d] client offline\n",socket.getInetAddress().toString(),socket.getPort());
                    break; 
                }

                //没有执行打印这条语句，说明上面的hasNext没有解除阻塞
                //说明客户端还没有发送数据过来，此时服务器就会阻塞等待
                System.out.println("收到客户端请求");

                String request = scanner.next();
                //2.根据请求计算响应
                String response = process(request);
                //3.把响应写回到客户端
                writer.println(response);

                //刷新缓冲区，确保数据发送到客户端
                writer.flush();

                System.out.printf("[%s:%d] req: %s, resp: %s",socket.getInetAddress().toString(),socket.getPort(),request,response);
            }
    } catch (IOException e) {
        e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        EchoServer echoServer = new EchoServer(9090);
        echoServer.start();
    }
}
